﻿using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Hosting.Internal;
using Sgr.Data;
using Sgr.Domain.Uow;
using Sgr.EntityFrameworkCore;
using Sgr.MediatR.Behaviors;
using Sgr.Utilities;

namespace Xunit.Sgr.Tests
{
    public class SgrIntegrationTestFixture : IDisposable
    {
        public IServiceProvider ServiceProvider { get; }
        public IConfiguration Configuration { get; }
        public IHostEnvironment Environment { get; }

        public SgrIntegrationTestFixture()
        {
            // 创建配置
            Configuration = CreateConfiguration();

            // 创建环境
            Environment = CreateHostEnvironment();

            // 创建服务集合
            var services = new ServiceCollection();

            // 配置服务
            ConfigureServices(services);

            ServiceProvider = services.BuildServiceProvider();

            // 初始化数据库
            InitializeDatabase();
        }

        /// <summary>
        /// 创建配置
        /// </summary>
        protected virtual IConfiguration CreateConfiguration()
        {
            return new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", optional: true)
                .AddJsonFile($"appsettings.Testing.json", optional: true)
                .AddEnvironmentVariables()
                .Build();
        }

        /// <summary>
        /// 创建主机环境
        /// </summary>
        protected virtual IHostEnvironment CreateHostEnvironment()
        {
            return new HostingEnvironment
            {
                EnvironmentName = "Testing",
                ApplicationName = "Sgr.Admin.WebHost",
                ContentRootPath = Directory.GetCurrentDirectory()
            };
        }

        /// <summary>
        /// 配置服务
        /// </summary>
        protected virtual void ConfigureServices(IServiceCollection serviceCollection)
        {
            // 注入 IConfiguration 和 IHostEnvironment
            serviceCollection.AddSingleton(Configuration);
            serviceCollection.AddSingleton(Environment);

            serviceCollection.AddSgrEntityFrameworkCore();
            serviceCollection.AddSgrMysqlDbProvider();
            serviceCollection.AddSgrSqliteDbProvider();

            serviceCollection.AddSgrDbContext<SgrDbContext, SgrReadOnlyDbContext>();
            serviceCollection.AddSgrWeb(Configuration, Environment);

            serviceCollection.AddMediatR(cfg =>
            {
                cfg.RegisterServicesFromAssemblyContaining<SgrIntegrationTestFixture>();
                cfg.AddOpenBehavior(typeof(ValidatorBehavior<,>));
                cfg.AddOpenBehavior(typeof(TransactionBehavior<,>));
            });

            // 清理数据库链接配置，改为使用测试数据库
            serviceCollection.RemoveAll<IDataConnectionStringProvider>();
            serviceCollection.TryAddEnumerable(ServiceDescriptor.Singleton<IDataConnectionStringProvider, TestDataConnectionStringProvider>());

            serviceCollection.AddHttpContextAccessor();
            // 配置Minimal API 和 ProblemDetails 的JSON序列化
            serviceCollection.ConfigureHttpJsonOptions(options =>
            {
                JsonHelper.UpdateJsonSerializerOptions(options.SerializerOptions);
            });
            serviceCollection.AddControllers().AddJsonOptions(options => { JsonHelper.UpdateJsonSerializerOptions(options.JsonSerializerOptions); });
            serviceCollection.AddEndpointsApiExplorer();
            serviceCollection.AddSgrAuthentication(Configuration, true);
        }

        /// <summary>
        /// 初始化数据库
        /// </summary>
        protected virtual void InitializeDatabase()
        {
            IUnitOfWorkManager unitOfWorkManager = ServiceProvider.GetRequiredService<IUnitOfWorkManager>();
            IDatabaseSeed databaseSeed = ServiceProvider.GetRequiredService<IDatabaseSeed>();

            AsyncHelper.RunSync(async () =>
            {
                using (var uow = unitOfWorkManager.Begin(new UnitOfWorkOption()))
                {
                    await databaseSeed.SeedAsync();
                    await uow.CommitAsync();
                }
            });
        }

        public virtual void Dispose()
        {
            if (ServiceProvider is IDisposable disposable)
            {
                disposable.Dispose();
            }
            GC.SuppressFinalize(this);
        }
    }
}